﻿using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;

namespace WorkflowDesigner.UI
{
    public class ValidationEventArgs
    {
        public List<ShapeBase> Shapes { get; set; }

    }

    public delegate bool DoValidation(object sender, ValidationEventArgs args);

    /// <summary>
    /// 画布类
    /// </summary>
    internal class Canvas : ScrollableControl
    {

        public event DoValidation DoValidationEvent;

        private readonly ValidationEventArgs _validationEventArgs;

        protected virtual void RaiseValidationEvent()
        {
            DoValidationEvent?.Invoke(this, _validationEventArgs);
        }
        /// <summary>
        /// 画布中流程控件
        /// </summary>
        private readonly List<ShapeBase> _shapes;

        /// <summary>
        /// 绘图模式
        /// </summary>
        private DrawMode _drawMode = DrawMode.Normal;

        /// <summary>
        /// 显示模式
        /// </summary>
        public bool IsOnlyView { get; set; }

        public Canvas()
        {
            SetStyle(
                ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint, true);
            _shapes = new List<ShapeBase>();

            _validationEventArgs = new ValidationEventArgs {Shapes = _shapes};
        }

        /// <summary>
        /// 绘制背景网格
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
            if (!IsOnlyView) ControlPaint.DrawGrid(e.Graphics, ClientRectangle, new Size(10, 10), BackColor);
        }

        /// <summary>
        /// 绘制图形
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            var g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TranslateTransform(AutoScrollPosition.X, AutoScrollPosition.Y);
            _shapes.ForEach(x => x.Paint(e.Graphics));
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (IsOnlyView) return;
            if (e.Button == MouseButtons.Left)
            {

                if (_drawMode == DrawMode.DrawingShape) // 正在添加控件
                {
                    var drawingObj = _shapes.SingleOrDefault(x => x.IsCreating);
                    if (drawingObj == null)
                    {
                        _drawMode = DrawMode.Normal;
                        return;
                    }

                    if (drawingObj is ShapeLine) // 画线条起点
                    {
                        var shapeBase = _shapes.FirstOrDefault(x => !(x is ShapeLine) && x.Contian(e.Location));
                        if (shapeBase == null)
                        {
                            _drawMode = DrawMode.Normal;
                            _shapes.Remove(drawingObj);
                        }
                        else
                        {
                            var point = shapeBase.GetNearHandle(e.Location);

                            if (point != null)
                            {
                                drawingObj.X = point.Value.X;
                                drawingObj.Y = point.Value.Y;
                            }

                            _drawMode = DrawMode.DrawingLine;
                        }
                        Invalidate();
                    }
                    else
                    {

                        _drawMode = DrawMode.Normal;
                        drawingObj.IsCreating = false;
                        Invalidate();
                    }
                }
                else if (_drawMode == DrawMode.DrawingLine) // 画线条终点
                {
                    var drawingObj = _shapes.SingleOrDefault(x => x.IsCreating);
                    if (drawingObj == null)
                    {
                        _drawMode = DrawMode.Normal;
                        return;
                    }

                    drawingObj.Width = e.X - drawingObj.X;
                    drawingObj.Height = e.Y - drawingObj.Y;
                    _drawMode = DrawMode.Normal;
                    drawingObj.IsCreating = false;
                    Invalidate();
                }
            }
            else
            {
                if (_drawMode == DrawMode.Normal) return;
                _drawMode = DrawMode.Normal;
                var drawingObj = _shapes.SingleOrDefault(x => x.IsCreating);
                if (drawingObj == null) return;
                _shapes.Remove(drawingObj);
                ((System.IDisposable)drawingObj).Dispose();
                Invalidate();
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (IsOnlyView) return;
            if (e.Button != MouseButtons.Left) return;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (IsOnlyView) return;
            if (_drawMode == DrawMode.DrawingShape)
            {
                var drawingObj = _shapes.SingleOrDefault(x => x.IsCreating);
                if (drawingObj == null) return;
                drawingObj.X = e.X - drawingObj.Width / 2;
                drawingObj.Y = e.Y - drawingObj.Width / 2;
                Invalidate();
            }
            else if (_drawMode == DrawMode.DrawingLine)
            {
                var drawingObj = _shapes.SingleOrDefault(x => x.IsCreating);
                if (drawingObj == null) return;
                drawingObj.Width = e.X - drawingObj.X;
                drawingObj.Height = e.Y - drawingObj.Y;
                Invalidate();
            }
        }

        public void AddShape(ShapeBase shape)
        {
            if (_drawMode != DrawMode.Normal) return;
            if (shape is ShapeLine)
            {
                _shapes.Insert(0, shape);
            }
            else
            {
                _shapes.Add(shape);
            }

            _drawMode = DrawMode.DrawingShape;
        }
    }
}